#include <iostream>
#include <pthread.h> //原生线程库
#include <thread>    //C++11线程库
#include <string>
#include <cstring>
#include <unistd.h>
#include <cstdio>
class ThreadData
{
public:
    ThreadData(const std::string &name, int a, int b)
        : _name(name), _a(a), _b(b)
    {
    }
    int Excute()
    {
        _result = _a + _b;
    }
    int Resurt()
    {
        return _result;
    }
    std::string Name()
    {
        return _name;
    }
    ~ThreadData()
    {
    }

private:
    std::string _name;
    int _a;
    int _b;
    int _result;
};

// 全局变量在线程内是共享的 和static 一样在栈区
int argv = 100; // 5.全局变量是线程共享的 线程都可以看到

std::string toHex(pthread_t tid)
{
    // 进程内的函数在栈上，线程共享
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%lx", tid);
    return buffer;
}

// 该线程返回值是void* 不直到返回值是什么类型
// 传进来的是字符串 名字
void *rountine1(void *args) // 不可重入函数(多个线程调用同一个函数，可能会错乱)--之后得同步互斥
{
    // std::string name = static_cast<const char *>(args);
    std::string name = static_cast<const char *>(args);
    while (true)
    {
        // 不加保护的情况下，显示器文件就是共享资源(都可以调用toHex函数)
        std::cout << "我是新线程，我的名字是: " << name << ", my tid is: " << toHex(pthread_self()) << ",全局变量(修改): " << argv << std::endl;
        argv++;
        sleep(1);
        break; // 检测此线程推出后main线程回收
               //  int *p = nullptr; //6.一个线程异常 其他线程和 对应的进程都会一起崩掉
               //  *p = 100;
    }

    return 0; // 线程退出方式1：线程入口函数return,表示线程退出
}

// 传进来的是td对象
void *rountine2(void *args) // 不可重入函数    可能会错乱
{
    ThreadData *td = static_cast<ThreadData *>(args);
    while (true)
    {
        // 3.不加保护(锁)的情况下，显示器文件就是共享资源(都可以调用toHex函数) 多线程打印可能会打印错乱
        std::cout << "我是新线程，我的名字是: " << td->Name() << ", my tid is: " << toHex(pthread_self()) << ",全局变量(只是检测argv): " << argv << std::endl;
        td->Excute();
        sleep(1);

        break; // 检测此线程推出后main线程回收
    }
    // 8.返回值问题:返回值可以是变量,数字，指针，对象等
    int *p = new int(10); // 8.1在堆上new申请空间 新线程可以看到说明 堆空间是线程共享的 堆上的空间按也是共享的 谁拿着堆空间的入口地址谁就能访问该堆区
    return (void *)p;
    // return (void *)10;    //       返回值就是执行方法的返回值
    return td; // 8.2返回值是对象  返回值是对象的话  返回的是对象的指针
}

int main()
{
    // 1.新线程和main线程谁先运行不确定
    // 2.线程创建出来要对进程的时间片进行瓜分
    pthread_t tid1; // 定义一个线程  create创一个新线程
    ThreadData *td = new ThreadData("thread-1", 10, 20);
    // 8.传参问题：传递参数，可以是变量,数字，对象等 可以传递对象说明可以传递多个参数(传的是地址)
    pthread_create(&tid1, nullptr, rountine1, td); // 最后一个参数传一个td对象进去(指针)
    // pthread_create(&tid1, nullptr, rountine1, (void *)"thread-1"); // rountine变一下 就可以不同线程执行不同函数

    // 7.线程创建以后，也是要被等待回收的  因为：会有 类似僵尸进程的问题(必要理由) 为了知道新线程的结果(可选理由)

    void *ret = nullptr; ///**********这个ret就是routine的返回值10 ret来接收10 ***其类型和rountine的返回值相同***********和库有关
    int n = pthread_join(tid1, &ret);
    ThreadData *rtd = nullptr;                // 8.2返回值是对象  返回值是对象的话返回的是对象的指针
    int n = pthread_join(tid1, (void **)rtd); // 返回值是一个对象  等待线程结束回收

    if (n != 0)
    {
        std::cerr << "join error: " << n << strerror(n) << std::endl;
        return 1;
    } //                                      *(int*)ret 返回值是指针并解引用
    std::cout << "join success!" << "ret: " << *(int *)ret << std::endl; // void*强转int 8字节强转4字节 就可能会报错 或者longlong长整数
    //--------------- std::cout << "join success!" << "ret: " << ret->result() << std::endl; 返回值是对象返回值是对象的话返回的是对象的指针
    // ret 返回值是数字

    // 创建多个线程
    // pthread_t tid2;
    // pthread_create(&tid2, nullptr, rountine2, (void *)"thread-2");
    // pthread_t tid3;
    // pthread_create(&tid3, nullptr, rountine, (void *)"thread-3");
    // pthread_t tid4;
    // pthread_create(&tid4, nullptr, rountine, (void *)"thread-4");

    // std::cout << "new thread id: " << tid << std::endl; //用C++打印这里不建议
    printf("new thread id: 0x%lx\n", tid1); // 打印创建的新线程的id 且是十六进制
    // printf("new thread id: 0x%lx\n", tid2);
    // printf("new thread id: 0x%lx\n", tid3);
    // printf("new thread id: 0x%lx\n", tid4);

    while (true)
    {
        std::cout << "我是main线程..." << std::endl;
        sleep(1);
    }

    return 0;
}

// 测试创建线程成功
//  void *routine(void *args)
//  {
//      std::string name = static_cast<const char *>(args);
//      while (true)
//      {
//          std::cout << "我是新线程，我的名字是: " << name << std::endl;
//          sleep(1);
//      }
//      return 0;
//  }
//  int main()
//  {
//      pthread_t tid;
//      int n = pthread_create(&tid, nullptr, routine, (void *)"thread-1");
//      if (n != 0)  //返回值部位0说明创建线程失败
//      {
//          std::cout << "create thread error: " << strerror(n) << std::endl;
//          return 1;
//      }
//      while (true)
//      {
//          std::cout << "我是main线程..." << std::endl;
//          sleep(1);
//      }
//      return 0;
//  }